1 /* 2 * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.awt.image; 27 import java.awt.image.Raster; 28 import java.awt.image.WritableRaster; 29 import java.awt.image.RasterFormatException; 30 import java.awt.image.SampleModel; 31 import java.awt.image.BandedSampleModel; 32 import java.awt.image.DataBuffer; 33 import java.awt.image.DataBufferByte; 34 import java.awt.Rectangle; 35 import java.awt.Point; 36 37 /** 38 * This class defines a Raster with pixels consisting of multiple 39 * 8-bit samples stored in possibly separate arrays for each band. 40 * Operations on sets of pixels are performed on a given band in the 41 * Raster before moving on to the next band. The arrays used for 42 * storage may be distinct or shared between some or all of the bands. 43 * Each band additionally has an offset that is added to determine the 44 * DataBuffer location of each pixel. 45 * 46 * There is only one scanline stride for all bands. The pixel stride 47 * is always equal to one. This type of raster can be used with a 48 * ComponentColorModel. This class requires a BandedSampleModel. 49 * 50 */ 51 public class ByteBandedRaster extends SunWritableRaster { 52 53 /** Data offsets for each band of image data. */ 54 int[] dataOffsets; 55 56 /** Scanline stride of the image data contained in this Raster. */ 57 int scanlineStride; 58 59 /** The image data array. */ 60 byte[][] data; 61 62 /** A cached copy of minX + width for use in bounds checks. */ 63 private int maxX; 64 65 /** A cached copy of minY + height for use in bounds checks. */ 66 private int maxY; 67 68 /** 69 * Constructs a ByteBandedRaster with the given sampleModel. The 70 * Raster's upper left corner is origin and it is the same 71 * size as the SampleModel. A dataBuffer large 72 * enough to describe the Raster is automatically created. SampleModel 73 * must be of type BandedSampleModel. 74 * @param sampleModel The SampleModel that specifies the layout. 75 * @param origin The Point that specifies the origin. 76 */ 77 public ByteBandedRaster(SampleModel sampleModel, 78 Point origin) { 79 this(sampleModel, 80 sampleModel.createDataBuffer(), 81 new Rectangle(origin.x, 82 origin.y, 83 sampleModel.getWidth(), 84 sampleModel.getHeight()), 85 origin, 86 null); 87 } 88 89 /** 90 * Constructs a ByteBanded Raster with the given sampleModel 91 * and DataBuffer. The Raster's upper left corner is origin and 92 * it is the same size as the SampleModel. The DataBuffer is not 93 * initialized and must be a DataBufferShort compatible with SampleModel. 94 * SampleModel must be of type BandedSampleModel. 95 * @param sampleModel The SampleModel that specifies the layout. 96 * @param dataBuffer The DataBufferShort that contains the image data. 97 * @param origin The Point that specifies the origin. 98 */ 99 public ByteBandedRaster(SampleModel sampleModel, 100 DataBuffer dataBuffer, 101 Point origin) { 102 this(sampleModel, dataBuffer, 103 new Rectangle(origin.x , origin.y, 104 sampleModel.getWidth(), 105 sampleModel.getHeight()), 106 origin, null); 107 } 108 109 /** 110 * Constructs a ByteBandedRaster with the given sampleModel, 111 * DataBuffer, and parent. DataBuffer must be a DataBufferShort and 112 * SampleModel must be of type BandedSampleModel. 113 * When translated into the base Raster's 114 * coordinate system, aRegion must be contained by the base Raster. 115 * Origin is the coordinate in the new Raster's coordinate system of 116 * the origin of the base Raster. (The base Raster is the Raster's 117 * ancestor which has no parent.) 118 * 119 * Note that this constructor should generally be called by other 120 * constructors or create methods, it should not be used directly. 121 * @param sampleModel The SampleModel that specifies the layout. 122 * @param dataBuffer The DataBufferShort that contains the image data. 123 * @param aRegion The Rectangle that specifies the image area. 124 * @param origin The Point that specifies the origin. 125 * @param parent The parent (if any) of this raster. 126 */ 127 public ByteBandedRaster(SampleModel sampleModel, 128 DataBuffer dataBuffer, 129 Rectangle aRegion, 130 Point origin, 131 ByteBandedRaster parent) { 132 133 super(sampleModel, dataBuffer, aRegion, origin, parent); 134 this.maxX = minX + width; 135 this.maxY = minY + height; 136 137 if (!(dataBuffer instanceof DataBufferByte)) { 138 throw new RasterFormatException("ByteBandedRaster must have" + 139 "byte DataBuffers"); 140 } 141 DataBufferByte dbb = (DataBufferByte)dataBuffer; 142 143 if (sampleModel instanceof BandedSampleModel) { 144 BandedSampleModel bsm = (BandedSampleModel)sampleModel; 145 this.scanlineStride = bsm.getScanlineStride(); 146 int bankIndices[] = bsm.getBankIndices(); 147 int bandOffsets[] = bsm.getBandOffsets(); 148 int dOffsets[] = dbb.getOffsets(); 149 dataOffsets = new int[bankIndices.length]; 150 data = new byte[bankIndices.length][]; 151 int xOffset = aRegion.x - origin.x; 152 int yOffset = aRegion.y - origin.y; 153 for (int i = 0; i < bankIndices.length; i++) { 154 data[i] = stealData(dbb, bankIndices[i]); 155 dataOffsets[i] = dOffsets[bankIndices[i]] + 156 xOffset + yOffset*scanlineStride + bandOffsets[i]; 157 } 158 } else { 159 throw new RasterFormatException("ByteBandedRasters must have"+ 160 "BandedSampleModels"); 161 } 162 verify(false); 163 } 164 165 166 /** 167 * Returns a copy of the data offsets array. For each band the data 168 * offset is the index into the band's data array, of the first sample 169 * of the band. 170 */ 171 public int[] getDataOffsets() { 172 return (int[])dataOffsets.clone(); 173 } 174 175 /** 176 * Returns data offset for the specified band. The data offset 177 * is the index into the band's data array 178 * in which the first sample of the first scanline is stored. 179 * @param The band whose offset is returned. 180 */ 181 public int getDataOffset(int band) { 182 return dataOffsets[band]; 183 } 184 185 /** 186 * Returns the scanline stride -- the number of data array elements 187 * between a given sample and the sample in the same column 188 * of the next row in the same band. 189 */ 190 public int getScanlineStride() { 191 return scanlineStride; 192 } 193 194 /** 195 * Returns the pixel stride, which is always equal to one for 196 * a Raster with a BandedSampleModel. 197 */ 198 public int getPixelStride() { 199 return 1; 200 } 201 202 /** 203 * Returns a reference to the entire data array. 204 */ 205 public byte[][] getDataStorage() { 206 return data; 207 } 208 209 /** 210 * Returns a reference to the specific band data array. 211 */ 212 public byte[] getDataStorage(int band) { 213 return data[band]; 214 } 215 216 /** 217 * Returns the data elements for all bands at the specified 218 * location. 219 * An ArrayIndexOutOfBounds exception will be thrown at runtime 220 * if the pixel coordinate is out of bounds. 221 * A ClassCastException will be thrown if the input object is non null 222 * and references anything other than an array of transferType. 223 * @param x The X coordinate of the pixel location. 224 * @param y The Y coordinate of the pixel location. 225 * @param outData An object reference to an array of type defined by 226 * getTransferType() and length getNumDataElements(). 227 * If null an array of appropriate type and size will be 228 * allocated. 229 * @return An object reference to an array of type defined by 230 * getTransferType() with the request pixel data. 231 */ 232 public Object getDataElements(int x, int y, Object obj) { 233 if ((x < this.minX) || (y < this.minY) || 234 (x >= this.maxX) || (y >= this.maxY)) { 235 throw new ArrayIndexOutOfBoundsException 236 ("Coordinate out of bounds!"); 237 } 238 byte outData[]; 239 if (obj == null) { 240 outData = new byte[numDataElements]; 241 } else { 242 outData = (byte[])obj; 243 } 244 int off = (y-minY)*scanlineStride + (x-minX); 245 246 for (int band = 0; band < numDataElements; band++) { 247 outData[band] = data[band][dataOffsets[band] + off]; 248 } 249 250 return outData; 251 } 252 253 /** 254 * Returns an array of data elements from the specified 255 * rectangular region. 256 * An ArrayIndexOutOfBounds exception will be thrown at runtime 257 * if the pixel coordinates are out of bounds. 258 * A ClassCastException will be thrown if the input object is non null 259 * and references anything other than an array of transferType. 260 * <pre> 261 * byte[] bandData = (byte[])raster.getDataElement(x, y, w, h, null); 262 * int numDataElements = raster.getNumDataElements(); 263 * byte[] pixel = new byte[numDataElements]; 264 * // To find a data element at location (x2, y2) 265 * System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements, 266 * pixel, 0, numDataElements); 267 * </pre> 268 * @param x The X coordinate of the upper left pixel location. 269 * @param y The Y coordinate of the upper left pixel location. 270 * @param width Width of the pixel rectangle. 271 * @param height Height of the pixel rectangle. 272 * @param outData An object reference to an array of type defined by 273 * getTransferType() and length w*h*getNumDataElements(). 274 * If null an array of appropriate type and size will be 275 * allocated. 276 * @return An object reference to an array of type defined by 277 * getTransferType() with the request pixel data. 278 */ 279 public Object getDataElements(int x, int y, int w, int h, Object obj) { 280 if ((x < this.minX) || (y < this.minY) || 281 (x + w > this.maxX) || (y + h > this.maxY)) { 282 throw new ArrayIndexOutOfBoundsException 283 ("Coordinate out of bounds!"); 284 } 285 byte outData[]; 286 if (obj == null) { 287 outData = new byte[numDataElements*w*h]; 288 } else { 289 outData = (byte[])obj; 290 } 291 int yoff = (y-minY)*scanlineStride + (x-minX); 292 293 for (int c = 0; c < numDataElements; c++) { 294 int off = c; 295 byte[] bank = data[c]; 296 int dataOffset = dataOffsets[c]; 297 298 int yoff2 = yoff; 299 for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) { 300 int xoff = dataOffset + yoff2; 301 for (int xstart=0; xstart < w; xstart++) { 302 outData[off] = bank[xoff++]; 303 off += numDataElements; 304 } 305 } 306 } 307 308 return outData; 309 } 310 311 /** 312 * Returns a byte array of data elements from the specified rectangular 313 * region for the specified band. 314 * An ArrayIndexOutOfBounds exception will be thrown at runtime 315 * if the pixel coordinates are out of bounds. 316 * <pre> 317 * byte[] bandData = raster.getByteData(x, y, w, h, null); 318 * // To find the data element at location (x2, y2) 319 * byte bandElement = bandData[((y2-y)*w + (x2-x))]; 320 * </pre> 321 * @param x The X coordinate of the upper left pixel location. 322 * @param y The Y coordinate of the upper left pixel location. 323 * @param width Width of the pixel rectangle. 324 * @param height Height of the pixel rectangle. 325 * @param band The band to return. 326 * @param outData If non-null, data elements for all bands 327 * at the specified location are returned in this array. 328 * @return Data array with data elements for all bands. 329 */ 330 public byte[] getByteData(int x, int y, int w, int h, 331 int band, byte[] outData) { 332 // Bounds check for 'band' will be performed automatically 333 if ((x < this.minX) || (y < this.minY) || 334 (x + w > this.maxX) || (y + h > this.maxY)) { 335 throw new ArrayIndexOutOfBoundsException 336 ("Coordinate out of bounds!"); 337 } 338 if (outData == null) { 339 outData = new byte[scanlineStride*h]; 340 } 341 int yoff = (y-minY)*scanlineStride + (x-minX) + dataOffsets[band]; 342 343 if (scanlineStride == w) { 344 System.arraycopy(data[band], yoff, outData, 0, w*h); 345 } else { 346 int off = 0; 347 for (int ystart=0; ystart < h; ystart++, yoff += scanlineStride) { 348 System.arraycopy(data[band], yoff, outData, off, w); 349 off += w; 350 } 351 } 352 353 return outData; 354 } 355 356 /** 357 * Returns a byte array of data elements from the specified rectangular 358 * region. 359 * An ArrayIndexOutOfBounds exception will be thrown at runtime 360 * if the pixel coordinates are out of bounds. 361 * <pre> 362 * byte[] bandData = raster.getByteData(x, y, w, h, null); 363 * int numDataElements = raster.getNumDataElements(); 364 * byte[] pixel = new byte[numDataElements]; 365 * // To find a data element at location (x2, y2) 366 * System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements, 367 * pixel, 0, numDataElements); 368 * </pre> 369 * @param x The X coordinate of the upper left pixel location. 370 * @param y The Y coordinate of the upper left pixel location. 371 * @param width Width of the pixel rectangle. 372 * @param height Height of the pixel rectangle. 373 * @param outData If non-null, data elements for all bands 374 * at the specified location are returned in this array. 375 * @return Data array with data elements for all bands. 376 */ 377 public byte[] getByteData(int x, int y, int w, int h, byte[] outData) { 378 if ((x < this.minX) || (y < this.minY) || 379 (x + w > this.maxX) || (y + h > this.maxY)) { 380 throw new ArrayIndexOutOfBoundsException 381 ("Coordinate out of bounds!"); 382 } 383 if (outData == null) { 384 outData = new byte[numDataElements*scanlineStride*h]; 385 } 386 int yoff = (y-minY)*scanlineStride + (x-minX); 387 388 for (int c = 0; c < numDataElements; c++) { 389 int off = c; 390 byte[] bank = data[c]; 391 int dataOffset = dataOffsets[c]; 392 393 // REMIND: Should keep track if dataoffsets are in a nice order 394 int yoff2 = yoff; 395 for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) { 396 int xoff = dataOffset + yoff2; 397 for (int xstart=0; xstart < w; xstart++) { 398 outData[off] = bank[xoff++]; 399 off += numDataElements; 400 } 401 } 402 } 403 404 return outData; 405 } 406 407 /** 408 * Stores the data elements for all bands at the specified location. 409 * An ArrayIndexOutOfBounds exception will be thrown at runtime 410 * if the pixel coordinate is out of bounds. 411 * A ClassCastException will be thrown if the input object is non null 412 * and references anything other than an array of transferType. 413 * @param x The X coordinate of the pixel location. 414 * @param y The Y coordinate of the pixel location. 415 * @param inData An object reference to an array of type defined by 416 * getTransferType() and length getNumDataElements() 417 * containing the pixel data to place at x,y. 418 */ 419 public void setDataElements(int x, int y, Object obj) { 420 if ((x < this.minX) || (y < this.minY) || 421 (x >= this.maxX) || (y >= this.maxY)) { 422 throw new ArrayIndexOutOfBoundsException 423 ("Coordinate out of bounds!"); 424 } 425 byte inData[] = (byte[])obj; 426 int off = (y-minY)*scanlineStride + (x-minX); 427 for (int i = 0; i < numDataElements; i++) { 428 data[i][dataOffsets[i] + off] = inData[i]; 429 } 430 markDirty(); 431 } 432 433 /** 434 * Stores the Raster data at the specified location. 435 * An ArrayIndexOutOfBounds exception will be thrown at runtime 436 * if the pixel coordinate is out of bounds. 437 * @param x The X coordinate of the pixel location. 438 * @param y The Y coordinate of the pixel location. 439 * @param inRaster Raster of data to place at x,y location. 440 */ 441 public void setDataElements(int x, int y, Raster inRaster) { 442 int dstOffX = inRaster.getMinX() + x; 443 int dstOffY = inRaster.getMinY() + y; 444 int width = inRaster.getWidth(); 445 int height = inRaster.getHeight(); 446 if ((dstOffX < this.minX) || (dstOffY < this.minY) || 447 (dstOffX + width > this.maxX) || (dstOffY + height > this.maxY)) { 448 throw new ArrayIndexOutOfBoundsException 449 ("Coordinate out of bounds!"); 450 } 451 452 setDataElements(dstOffX, dstOffY, width, height, inRaster); 453 } 454 455 /** 456 * Stores the Raster data at the specified location. 457 * @param dstX The absolute X coordinate of the destination pixel 458 * that will receive a copy of the upper-left pixel of the 459 * inRaster 460 * @param dstY The absolute Y coordinate of the destination pixel 461 * that will receive a copy of the upper-left pixel of the 462 * inRaster 463 * @param width The number of pixels to store horizontally 464 * @param height The number of pixels to store vertically 465 * @param inRaster Raster of data to place at x,y location. 466 */ 467 private void setDataElements(int dstX, int dstY, 468 int width, int height, 469 Raster inRaster) { 470 // Assume bounds checking has been performed previously 471 if (width <= 0 || height <= 0) { 472 return; 473 } 474 475 int srcOffX = inRaster.getMinX(); 476 int srcOffY = inRaster.getMinY(); 477 Object tdata = null; 478 479 // // REMIND: Do something faster! 480 // if (inRaster instanceof ByteBandedRaster) { 481 // } 482 483 for (int startY=0; startY < height; startY++) { 484 // Grab one scanline at a time 485 tdata = inRaster.getDataElements(srcOffX, srcOffY+startY, 486 width, 1, tdata); 487 setDataElements(dstX, dstY+startY, width, 1, tdata); 488 } 489 } 490 491 /** 492 * Stores an array of data elements into the specified rectangular 493 * region. 494 * An ArrayIndexOutOfBounds exception will be thrown at runtime 495 * if the pixel coordinates are out of bounds. 496 * A ClassCastException will be thrown if the input object is non null 497 * and references anything other than an array of transferType. 498 * The data elements in the 499 * data array are assumed to be packed. That is, a data element 500 * for the nth band at location (x2, y2) would be found at: 501 * <pre> 502 * inData[((y2-y)*w + (x2-x))*numDataElements + n] 503 * </pre> 504 * @param x The X coordinate of the upper left pixel location. 505 * @param y The Y coordinate of the upper left pixel location. 506 * @param w Width of the pixel rectangle. 507 * @param h Height of the pixel rectangle. 508 * @param inData An object reference to an array of type defined by 509 * getTransferType() and length w*h*getNumDataElements() 510 * containing the pixel data to place between x,y and 511 * x+h, y+h. 512 */ 513 public void setDataElements(int x, int y, int w, int h, Object obj) { 514 if ((x < this.minX) || (y < this.minY) || 515 (x + w > this.maxX) || (y + h > this.maxY)) { 516 throw new ArrayIndexOutOfBoundsException 517 ("Coordinate out of bounds!"); 518 } 519 byte inData[] = (byte[])obj; 520 int yoff = (y-minY)*scanlineStride + (x-minX); 521 522 for (int c = 0; c < numDataElements; c++) { 523 int off = c; 524 byte[] bank = data[c]; 525 int dataOffset = dataOffsets[c]; 526 527 int yoff2 = yoff; 528 for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) { 529 int xoff = dataOffset + yoff2; 530 for (int xstart=0; xstart < w; xstart++) { 531 bank[xoff++] = inData[off]; 532 off += numDataElements; 533 } 534 } 535 } 536 537 markDirty(); 538 } 539 540 /** 541 * Stores a byte array of data elements into the specified rectangular 542 * region. 543 * An ArrayIndexOutOfBounds exception will be thrown at runtime 544 * if the pixel coordinates are out of bounds. 545 * The data elements in the 546 * data array are assumed to be packed. That is, a data element 547 * for the nth band at location (x2, y2) would be found at: 548 * <pre> 549 * inData[((y2-y)*w + (x2-x))*numDataElements + n] 550 * </pre> 551 * @param x The X coordinate of the upper left pixel location. 552 * @param y The Y coordinate of the upper left pixel location. 553 * @param w Width of the pixel rectangle. 554 * @param h Height of the pixel rectangle. 555 * @param band The band to set. 556 * @param inData The data elements to be stored. 557 */ 558 public void putByteData(int x, int y, int w, int h, 559 int band, byte[] inData) { 560 // Bounds check for 'band' will be performed automatically 561 if ((x < this.minX) || (y < this.minY) || 562 (x + w > this.maxX) || (y + h > this.maxY)) { 563 throw new ArrayIndexOutOfBoundsException 564 ("Coordinate out of bounds!"); 565 } 566 int yoff = (y-minY)*scanlineStride + (x-minX) + dataOffsets[band]; 567 int xoff; 568 int off = 0; 569 int xstart; 570 int ystart; 571 572 if (scanlineStride == w) { 573 System.arraycopy(inData, 0, data[band], yoff, w*h); 574 } else { 575 for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) { 576 System.arraycopy(inData, off, data[band], yoff, w); 577 off += w; 578 } 579 } 580 581 markDirty(); 582 } 583 584 /** 585 * Stores a byte array of data elements into the specified rectangular 586 * region. 587 * An ArrayIndexOutOfBounds exception will be thrown at runtime 588 * if the pixel coordinates are out of bounds. 589 * The data elements in the 590 * data array are assumed to be packed. That is, a data element 591 * for the nth band at location (x2, y2) would be found at: 592 * <pre> 593 * inData[((y2-y)*w + (x2-x))*numDataElements + n] 594 * </pre> 595 * @param x The X coordinate of the upper left pixel location. 596 * @param y The Y coordinate of the upper left pixel location. 597 * @param w Width of the pixel rectangle. 598 * @param h Height of the pixel rectangle. 599 * @param inData The data elements to be stored. 600 */ 601 public void putByteData(int x, int y, int w, int h, byte[] inData) { 602 if ((x < this.minX) || (y < this.minY) || 603 (x + w > this.maxX) || (y + h > this.maxY)) { 604 throw new ArrayIndexOutOfBoundsException 605 ("Coordinate out of bounds!"); 606 } 607 int yoff = (y-minY)*scanlineStride + (x-minX); 608 609 for (int c = 0; c < numDataElements; c++) { 610 int off = c; 611 byte[] bank = data[c]; 612 int dataOffset = dataOffsets[c]; 613 614 int yoff2 = yoff; 615 for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) { 616 int xoff = dataOffset + yoff2; 617 for (int xstart=0; xstart < w; xstart++) { 618 bank[xoff++] = inData[off]; 619 off += numDataElements; 620 } 621 } 622 } 623 624 markDirty(); 625 } 626 627 /** 628 * Creates a Writable subraster given a region of the raster. The x and y 629 * coordinates specify the horizontal and vertical offsets 630 * from the upper-left corner of this raster to the upper-left corner 631 * of the subraster. A subset of the bands of the parent Raster may 632 * be specified. If this is null, then all the bands are present in the 633 * subRaster. A translation to the subRaster may also be specified. 634 * Note that the subraster will reference the same 635 * DataBuffers as the parent raster, but using different offsets. 636 * @param x X offset. 637 * @param y Y offset. 638 * @param width Width of the subraster. 639 * @param height Height of the subraster. 640 * @param x0 Translated X origin of the subraster. 641 * @param y0 Translated Y origin of the subraster. 642 * @param bandList Array of band indices. 643 * @exception RasterFormatException 644 * if the specified bounding box is outside of the parent raster. 645 */ 646 public WritableRaster createWritableChild (int x, int y, 647 int width, int height, 648 int x0, int y0, 649 int bandList[]) { 650 651 if (x < this.minX) { 652 throw new RasterFormatException("x lies outside raster"); 653 } 654 if (y < this.minY) { 655 throw new RasterFormatException("y lies outside raster"); 656 } 657 if ((x+width < x) || (x+width > this.width + this.minX)) { 658 throw new RasterFormatException("(x + width) is outside raster") ; 659 } 660 if ((y+height < y) || (y+height > this.height + this.minY)) { 661 throw new RasterFormatException("(y + height) is outside raster"); 662 } 663 664 SampleModel sm; 665 666 if (bandList != null) 667 sm = sampleModel.createSubsetSampleModel(bandList); 668 else 669 sm = sampleModel; 670 671 int deltaX = x0 - x; 672 int deltaY = y0 - y; 673 674 return new ByteBandedRaster(sm, 675 dataBuffer, 676 new Rectangle(x0,y0,width,height), 677 new Point(sampleModelTranslateX+deltaX, 678 sampleModelTranslateY+deltaY), 679 this); 680 } 681 682 /** 683 * Creates a subraster given a region of the raster. The x and y 684 * coordinates specify the horizontal and vertical offsets 685 * from the upper-left corner of this raster to the upper-left corner 686 * of the subraster. A subset of the bands of the parent Raster may 687 * be specified. If this is null, then all the bands are present in the 688 * subRaster. A translation to the subRaster may also be specified. 689 * Note that the subraster will reference the same 690 * DataBuffers as the parent raster, but using different offsets. 691 * @param x X offset. 692 * @param y Y offset. 693 * @param width Width (in pixels) of the subraster. 694 * @param height Height (in pixels) of the subraster. 695 * @param x0 Translated X origin of the subraster. 696 * @param y0 Translated Y origin of the subraster. 697 * @param bandList Array of band indices. 698 * @exception RasterFormatException 699 * if the specified bounding box is outside of the parent raster. 700 */ 701 public Raster createChild (int x, int y, 702 int width, int height, 703 int x0, int y0, 704 int bandList[]) { 705 return createWritableChild(x, y, width, height, x0, y0, bandList); 706 } 707 708 /** 709 * Creates a Raster with the same layout but using a different 710 * width and height, and with new zeroed data arrays. 711 */ 712 public WritableRaster createCompatibleWritableRaster(int w, int h) { 713 if (w <= 0 || h <=0) { 714 throw new RasterFormatException("negative "+ 715 ((w <= 0) ? "width" : "height")); 716 } 717 718 SampleModel sm = sampleModel.createCompatibleSampleModel(w,h); 719 720 return new ByteBandedRaster(sm, new Point(0,0)); 721 } 722 723 /** 724 * Creates a Raster with the same layout and the same 725 * width and height, and with new zeroed data arrays. If 726 * the Raster is a subRaster, this will call 727 * createCompatibleRaster(width, height). 728 */ 729 public WritableRaster createCompatibleWritableRaster() { 730 return createCompatibleWritableRaster(width, height); 731 } 732 733 /** 734 * Verify that the layout parameters are consistent with 735 * the data. If strictCheck 736 * is false, this method will check for ArrayIndexOutOfBounds conditions. If 737 * strictCheck is true, this method will check for additional error 738 * conditions such as line wraparound (width of a line greater than 739 * the scanline stride). 740 * @return String Error string, if the layout is incompatible with 741 * the data. Otherwise returns null. 742 */ 743 private void verify (boolean strictCheck) { 744 // Make sure data for Raster is in a legal range 745 for (int i=0; i < dataOffsets.length; i++) { 746 if (dataOffsets[i] < 0) { 747 throw new RasterFormatException("Data offsets for band "+i+ 748 "("+dataOffsets[i]+ 749 ") must be >= 0"); 750 } 751 } 752 753 int maxSize = 0; 754 int size; 755 756 for (int i=0; i < numDataElements; i++) { 757 size = (height-1)*scanlineStride + (width-1) + dataOffsets[i]; 758 if (size > maxSize) { 759 maxSize = size; 760 } 761 } 762 763 if (data.length == 1) { 764 if (data[0].length < maxSize*numDataElements) { 765 throw new RasterFormatException("Data array too small "+ 766 "(it is "+data[0].length+ 767 " and should be "+ 768 (maxSize*numDataElements)+ 769 " )"); 770 } 771 } 772 else { 773 for (int i=0; i < numDataElements; i++) { 774 if (data[i].length < maxSize) { 775 throw new RasterFormatException("Data array too small "+ 776 "(it is "+data[i].length+ 777 " and should be "+ 778 maxSize+" )"); 779 } 780 } 781 } 782 } 783 784 public String toString() { 785 return new String ("ByteBandedRaster: width = "+width+" height = " 786 + height 787 +" #bands "+numDataElements 788 +" minX = "+minX+" minY = "+minY); 789 } 790 791 }